<template>
    <n-modal v-model:show="showModal" class="form_dialog">
        <n-spin :show="state.loading" :content-style="{ '--n-opacity-spinning': 1 }">
            <n-card :style="`width: ${cardWidth}px`" :title="title" :bordered="false" size="huge" role="dialog"
                aria-modal="true">
                <n-form :model="state.form" :label-width="labelWidth" ref="formRef">
                    <template v-for="(item, index) in formConfig">
                        <span class="required_text" v-if="item.required">*</span>
                        <n-form-item :label="item.label" v-if="item.type !== ''">
                            <n-input v-model:value="state.form[item.prop]" :placeholder="item.placeholder"
                                v-if="item.type === 'input'" @keyup.enter="onSubmit(formRef)" />

                            <n-select v-model:value="state.form[item.prop]" :placeholder="item.placeholder"
                                v-if="item.type === 'select'" :options="item.options">
                            </n-select>

                            <Editor :placeholder="item.editor?.placeholder" :mode="'default'"
                                v-model:get-html="state.form[item.prop]" v-if="item.type === 'editor'" ref="editorRef">
                            </Editor>

                            <Upload :btnText="item.btnText" :ext="ext" :size="size" v-if="item.type === 'upload'"
                                @update="onUploadSuccess" ref="uploadRef"></Upload>

                            <template v-else>
                                <slot :name="item.type" :data="item" :state="state"></slot>
                            </template>
                        </n-form-item>
                    </template>
                </n-form>

                <template #footer>
                    <div class="form_footer">
                        <n-space>
                            <n-button @click="showModal = false">取消</n-button>
                            <n-button type="primary" @click="onSubmit(formRef)">提交</n-button>
                        </n-space>
                    </div>
                </template>
            </n-card>
        </n-spin>
    </n-modal>
</template>

<script setup>
/**
 * @description 表单组件 需要父组件绑定 onSubmit 回调函数 ，此函数返回表单填写数据，父组件根据返回数据做相应处理 组件默
 * @prop {Object} formConfig 表单配置 参考/src/views/joinUs/data.js formConfig1
 * formConfig 项包含 label 表单标题 prop 表单字段名 placeholder 表单未填写占位符 required 是否必填 type 表单类型
 * options 表单选项 type 为 select 时有效
 * btnText 上传按钮文字 type 为 upload 时有效
 * 
 * @prop {Number} cardWidth 卡片宽度 默认800
 * @prop {Array} ext 上传文件类型 默认['pdf', 'docx', 'doc']
 * @prop {Number} size 上传文件大小 默认10M
 * @prop {Number} labelWidth 标签宽度 默认auto
 * @author fhl
 * @date 2024.09.26
 */

import { ref, reactive, nextTick, onMounted } from "vue"
import { NModal, NCard, useMessage, NSpin, NForm, NSpace, NFormItem, NInput, NSelect, NButton } from "naive-ui"
import Upload from "@/components/upload/index.vue"
import Editor from '@/components/editor/index.vue'

const emits = defineEmits(['onSubmit'])

const props = defineProps({
    formConfig: Object,
    cardWidth: {
        type: Number,
        default: 800
    },
    ext: {
        type: Array,
        default: () => ['pdf', 'docx', 'doc']
    },
    size: {
        type: Number,
        default: 10
    },
    title: {
        type: String,
        default: ''
    },
    labelWidth: {
        type: [String, Number],
        default: 'auto'
    }
})

const showModal = ref(false)
const formRef = ref()
const uploadRef = ref()
const editorRef = ref()
const message = useMessage()

const state = reactive({
    form: {},
    loading: false
});

const openModel = async (initialData = {}) => {
    showModal.value = true;

    await nextTick();
    initForm(initialData);
    formRef.value.restoreValidation();
};


const closeModel = () => {
    showModal.value = false
}

const closeLoading = () => {
    state.loading = false
}

const initForm = (initialData) => {
    if (initialData == void (0)) return;

    state.form = initialData
};

const onUploadSuccess = (res) => {
    message.success('Upload success')

    state.form.cvUrl = res.data
}

const validateForm = async (formEl) => {
    if (!formEl) return false;

    const valid = props.formConfig.every(item => {
        if (item.required && !state.form[item.prop]) {
            message.error(`message.formI18nErrTips.required`, { name: item.label });
            return false;
        }
        return true;
    });

    if (!valid) return false;

    return await formEl.validate(async (valid) => {
        return valid;
    });
};

const onSubmit = async (formRef) => {
    const isValid = await validateForm(formRef);
    if (isValid) {
        state.loading = true

        emits('onSubmit', state.form)
    }
}

onMounted(() => {
    initForm();
})

defineExpose({
    openModel,
    closeModel,
    closeLoading
})
</script>

<style lang='less'>
.form_dialog {
    .n-form {
        position: relative;

        .required_text {
            position: absolute;
            left: -10px;
            color: red;
        }
    }
}

.form_footer {
    display: flex;
    justify-content: center;
    align-items: center;
}
</style>